<template>
  <n-select
    v-bind="{
      filterable: true,
      clearable: true,
      ...attrs,
    }"
    :options="data.list"
    :loading="data.loading"
    :label-field="isString ? dictLabelKey : labelKey"
    :value-field="isString ? dictValueKey : valueKey"
    @search="(keyword) => (hasAttr(attrs.remote) ? methods.remoteMethods(keyword) : null)"
  />
</template>
<script setup lang="jsx">
import { getSelArrDicts } from '@/api/dict'
import { debounce } from 'lodash-es'
defineOptions({ name: 'AsyncSelect' })
const attrs = useAttrs()
const props = defineProps({
  options: {
    type: [String, Number, Array, Function],
    default: () => [],
  },
  labelKey: {
    type: String,
    default: 'label',
  },
  valueKey: {
    type: String,
    default: 'value',
  },
  disabledKey: {
    type: [String, Function],
    default: 'disable',
  },
  initRemote: {
    type: Boolean,
    default: false,
  },
  dictLabelKey: {
    type: String,
    default: 'name',
  },
  dictValueKey: {
    type: String,
    default: 'code',
  },
  isEmptyQuery: {
    type: Boolean,
    default: true,
  },
})
const emits = defineEmits(['load-dict'])
const isString = computed(() => typeof props.options === 'string')
const data = reactive({
  list: [],
  loading: false,
})
function hasAttr(attr) {
  return attr || attr === ''
}
const methods = reactive({
  async initOptions() {
    if (typeof props.options === 'string') {
      data.list = await getSelArrDicts({ codes: props.options }).then(
        (res) => res.data[props.options]
      )
      emits('load-dict', data.list)
      return null
    }
    if (typeof props.options === 'number') {
      data.list = Array.from({ length: props.options }).map((_, index) => ({
        [`${props.labelKey}`]: index,
        [`${props.valueKey}`]: index,
      }))
      return null
    }
    if (Array.isArray(props.options)) {
      data.list = props.options
      return null
    }
    if (typeof props.options === 'function') {
      if (hasAttr(attrs.remote) && !props.initRemote) {
        data.list = []
        return null
      } else {
        const defaultVal = hasAttr(attrs.multiple) ? [] : ''
        data.list = await props.options('', attrs.value ?? defaultVal)
        return null
      }
    }
  },
  remoteMethods: debounce(async function (keyword) {
    if (keyword !== '') {
      data.loading = true
      data.list = await props.options(keyword)
      data.loading = false
    } else {
      if (props.isEmptyQuery) {
        const defaultVal = hasAttr(attrs.multiple) ? [] : ''
        data.list = await props.options('', attrs.value ?? defaultVal)
      } else {
        data.list = []
      }
    }
  }, 300),
  async resetList() {
    if (hasAttr(attrs.remote)) {
      data.list = await props.options()
    }
  },
  findItem(val) {
    return data.list.find((item) => item[props.valueKey] === val)
  },
  initIsDisable() {
    if (typeof props.disabledKey === 'string') {
      methods.isDisable = (item) => item[props.disabledKey]
      return null
    }
    if (typeof props.disabledKey === 'function') {
      methods.isDisable = props.disabledKey
      return null
    }
  },
  isDisable() {},
})
onBeforeMount(() => {
  methods.initOptions()
  methods.initIsDisable()
})
watch(
  () => props.options,
  () => {
    methods.initOptions()
  }
)
defineExpose({
  resetList: methods.resetList,
  findItem: methods.findItem,
})
</script>
<style lang="scss" scoped></style>
